function UserBubble(param) {

	var that = this;
	
	this.j_bubble_trigger = null;
	this.j_bubble = null;
	this.j_bubble_username = null;
	this.j_bubble_from = null;
	this.j_bubble_arrow = null;
	
	var open_timer = { timer : null, activate : false };
	var close_timer = { timer : null, activate : false };
	
	var open_bubble_data = null;
	var user_bubble_arrow_border_width = 5;
	
	function __construct(p) {
		for(pkey in p) {
			if(pkey[0] != "_") {
				that[pkey] = p[pkey];
			}
		}
		that.j_bubble_trigger.live("mouseenter", triggerMouseEnter).live("mouseleave", triggerMouseLeave);
		that.j_bubble.mouseenter(bubbleMouseEnter).mouseleave(bubbleMouseLeave);
		
	}
	
	function triggerMouseEnter(e) {
		var user_bubble_data = jq(this).data("user-bubble");
		clearTimer(close_timer);
		open_bubble_data = { "user_data" : user_bubble_data.user_data, "j_triggered" : jq(this) };
		if(user_bubble_data.opening_delay && !that.j_bubble.is(":visible")) {
			setTimer(openBubble, user_bubble_data.opening_delay, open_timer);
		}
		else {
			openBubble();
		}
	}

	function triggerMouseLeave(e) {
		setTimer(closeBubble, 300, close_timer);
	}
	
	function bubbleMouseEnter(e) {
		clearTimer(close_timer);
	}
	
	function bubbleMouseLeave(e) {
		setTimer(closeBubble, 300, close_timer);
	}
	
	function openBubble() {
		var u = open_bubble_data.user_data;
		var triggered = open_bubble_data.j_triggered;
		var triggered_username = u.username;
		var triggered_from = u.from;
		var triggered_offset = triggered.offset();
		that.j_bubble_username.text(triggered_username);
		that.j_bubble_from.text(triggered_from);
		var bubble_width = that.j_bubble.outerWidth();
		var bubble_height = that.j_bubble.outerHeight();
		
		var top_interval = 2;
		
		var bubble_arrow_left = bubble_width/2 - user_bubble_arrow_border_width;
		var bubble_left = triggered_offset.left - ((bubble_width - triggered.width())/2);
		var bubble_top = triggered_offset.top - (bubble_height + user_bubble_arrow_border_width + top_interval);
		
		that.j_bubble_arrow.css({ left : bubble_arrow_left + "px" });
		that.j_bubble.css({ top : bubble_top + "px", left : bubble_left + "px" }).show();
	}
	
	function closeBubble() {
		that.j_bubble.hide();
	}
	
	function setTimer(fct, delay, timer_obj) {
		if(timer_obj.activate) {
			clearTimer(timer_obj);
		}
		timer_obj.timer = setTimeout(function() { fct(); timer_obj.activate = false; }, delay);
		timer_obj.activate = true;
	}
	
	function clearTimer(timer_obj) {
		clearTimeout(timer_obj.timer);
		timer_obj.activate = false;		
	}
	
	/* --- calculating text width --- */
	/*
	function textWidth(obj) {
  		var html_org = obj.html();
  		var html_calc = '<span>' + html_org + '</span>';
  		obj.html(html_calc);
  		var width = obj.find('span:first').width();
  		obj.html(html_org);
  		return width;
	}
	*/
	__construct(param);
	
}

	
